use std::cell::RefCell;
use std::rc::Rc;
use crate::List::{Cons,Nil};

#[derive(Debug)]
enum List {
    Cons(i32, RefCell<Rc<List>>),
    Nil,
}

impl List {
    fn tail(&self) -> Option<&RefCell<Rc<List>>> {
        match self {
            Cons(_, item) => Some(item),
            Nil => None,
        }
    }
}

#[test] // 使用 cargo test -p test_leak -- --nocapture 来输出println! 信息
fn test_leak () {
    // 首先了解一个无关的话题

    // // 问题1
    // let num_list = [1,2,3];
    // assert_eq!(6, num_list.iter().sum(), "没问题。") ;
    // let num_list2 = Rc::new(&num_list); // 把列表包装到Rc 智能指针中。
    // assert_eq!(6, num_list2.iter().sum(), "这个我就个问题为什么不是不需要解引用呢，我理解上应该需要解引用才能调用 iter() 呀。");
    //
    // // 问题2
    // let num_list = [1,2,3];
    // let _ = Rc::new(num_list); // 如果这样 num_list 不是应该失去所有权么
    // assert_eq!(6, num_list.iter().sum(), "如果所有权传递到Rc::new() 这个应该没法使用了，为什么还能用呢？") ;
    //
    // // 另外试试其他的，Box 也是一样的表现
    // let num_list = [1,2,3];
    // assert_eq!(6, num_list.iter().sum(), "这个很好理解没问，这里要留意 .iter() 方法，这是是列表的方法。") ;
    // let num_list2 = Box::new(num_list); // 放到智能指针中。
    // assert_eq!(6, num_list2.iter().sum());
    // assert_eq!(6, num_list.iter().sum());

    // 创建一个多引用指针Rc，里面是一个List::Cons枚举，这个枚举里面的二值，是一个可变的多引用指针。
    let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));
    println!("a initial rc count = {} 应该是1", Rc::strong_count(&a)); // 应该是1
    // 为什么可以直接调用.tail()，我理解上不需要解引用么。
    println!("a next item = {:?}", a.tail());

    // 创建一个B ，B的指针元素指向a
    let b = Rc::new((Cons(10, RefCell::new(Rc::clone(&a)))));
    // 打印 a 的 rc count
    println!("a rc count after b creation = {} 应该是2 ", Rc::strong_count(&a)); //应该是2
    println!("b initial rc count = {} 应该是1", Rc::strong_count(&b)); // 应该是1
    println!("b next item = {:?}", b.tail());

    // 准备建立一个循环链，就是b->a->b , 这就需要 RefCell 才能实现了
    if let Some(link) = a.tail() {
        // 获取 a  的那个 RefCall 变量，现在是 Nil
        // 然后把 a 的链表指回b 这样一个死循环链就形成了
        *link.borrow_mut() = Rc::clone(&b);
    }

    println!("a rc count after changing a = {}", Rc::strong_count(&a));
    println!("b rc count after changing b = {}", Rc::strong_count(&b));

    // 取消下面的注释就可以看到堆栈的溢出效果
    // println!("b next item = {:?}", b.tail());
}